import FrameLog from "../../extensions/FrameLog";
import Singleton from "../design-pattern/Singleton";
import StorageMgr from "./StorageMgr";

const { ccclass, property } = cc._decorator;
/**声音数据 */
type AudioData = {
    musicCtrl: boolean,
    effectCtrl: boolean,
    musicVolume: number,
    effectVolume: number
}
/**声音开关类型 */
export enum AudioType {
    /**音乐开关 */
    musicCtrl,
    /**音效开关 */
    effectCtrl
}
@ccclass
export default class AudioMgr extends Singleton {

    /**声音key */
    private readonly _audioKey = "audioKey";
    /**声音路径 */
    private readonly _audioPath = `audio`
    /**最近播放的音乐 */
    private curMusicName: string = ``;
    /**声音设置 */
    private _audioData: AudioData = {
        /**音乐开关 */
        musicCtrl: true,
        /**音效开关 */
        effectCtrl: true,
        /** 音乐音量*/
        musicVolume: 1.0,
        /** 特效音量*/
        effectVolume: 1.0
    }

    /**声音初始化 */
    public init() {
        //初始化声音设置
        let obj = StorageMgr.getInstance().get(this._audioKey)
        if (obj) {
            this._audioData.musicCtrl = obj.musicCtrl;
            this._audioData.effectCtrl = obj.effectCtrl;
            this._audioData.musicVolume = obj.musicVolume;
            this._audioData.effectVolume = obj.effectVolume;
        }
    }

    /**保存声音设置 */
    public save(key: AudioType) {
        //如果设置的是音乐开关
        if (key === AudioType.musicCtrl) {
            this._audioData.musicCtrl = !this._audioData.musicCtrl
            if (!this._audioData.musicCtrl) {
                this.stopAllMusic()
            }
            else {
                this.playMusic(this.curMusicName, this._music.get(this.curMusicName).loop)
            }
        }
        //如果设置的是音效开关
        else {
            this._audioData.effectCtrl = !this._audioData.effectCtrl
        }
        //保存设置
        StorageMgr.getInstance().set(this._audioKey, this._audioData)
    }

    /** 所有音频信息*/
    private _clipMap: Map<string, cc.AudioClip> = new Map();
    /** 正在播放的音乐*/
    private _music: Map<string, { id: number; loop: boolean }> = new Map();
    /** 正在播放的音效*/
    private _effect: Map<string, { id: number; loop: boolean }> = new Map();

    /**添加音频 */
    public getClip(clipName: string, cb: (res: cc.AudioClip) => void) {
        if (this._clipMap[clipName])
            cb(this._clipMap[clipName])
        else {
            FrameLog.log("动态加载声音", this._audioPath + clipName)
            cc.resources.load<cc.AudioClip>(this._audioPath + clipName, cc.AudioClip, (err, audio) => {
                if (err) return;
                this._clipMap.set(clipName, audio)
                cb(audio)
            })
        }
    }
    /**
     * 设置音乐音量
     * @param value 音量值（0.0 ~ 1.0）
     */
    public setMusicVolume(value: number): void {
        if (value < 0.0) value = 0.0;
        else if (value > 1.0) value = 1.0;
        this._audioData.musicVolume = value;
        this._music.forEach((obj, clipName) => {
            cc.audioEngine.setVolume(obj.id, value)
        });
        StorageMgr.getInstance().set(this._audioKey, this._audioData)
    }

    /**
     * 设置特效音量
     * @param value 音量值（0.0 ~ 1.0）
     */
    public setEffectVolume(value: number): void {
        if (value < 0.0) value = 0.0;
        else if (value > 1.0) value = 1.0;
        this._audioData.effectVolume = value;
        this._effect.forEach((obj, clipName) => {
            cc.audioEngine.setVolume(obj.id, value)
        });
        StorageMgr.getInstance().set(this._audioKey, this._audioData)
    }

    /**
     * 播放音乐
     * @param clipName 音频名字
     * @param loop 是否循环
     */
    public playMusic(clipName: string, loop: boolean): void {
        this.getClip(clipName, (res) => {
            //加载到音频,没有关闭音乐
            if (res && this._audioData.musicCtrl) {
                let id = cc.audioEngine.playMusic(res, loop)
                this._music.set(clipName, { id: id, loop: loop })
            }
        })
    }

    /**
     * 停止音乐
     * @param clipName 音频名字
     */
    public stopMusic(clipName: string): void {
        if (!this._music.has(clipName)) return;
        cc.audioEngine.stop(this._music.get(clipName).id);
        this._music.delete(clipName);
    }

    /**
     * 停止所有音乐
     */
    public stopAllMusic(): void {
        this._music.forEach((id, clipName) => this.stopMusic(clipName));
    }

    /**
     * 暂停音乐
     * @param clipName 音频名字
     */
    public pauseMusic(clipName: string): void {
        if (!this._music.has(clipName)) return;
        cc.audioEngine.pause(this._music.get(clipName).id);
    }

    /**
     * 暂停所有音乐
     */
    public pauseAllMusic(): void {
        this._music.forEach((id, clipName) => this.pauseMusic(clipName));
    }

    /**
     * 恢复音乐
     * @param clipName 音频名字
     */
    public resumeMusic(clipName: string): void {
        if (!this._music.has(clipName)) return;
        cc.audioEngine.resume(this._music.get(clipName).id);
    }

    /**
     * 恢复所有音乐
     */
    public resumeAllMusic(): void {
        this._music.forEach((id, clipName) => this.resumeMusic(clipName));
    }

    /**
     * 播放音效
     * @param clipName 音频名字
     * @param loop 是否循环
     */
    public playEffect(clipName: string, loop: boolean): void {
        this.getClip(clipName, (res) => {
            //加载到音频,没有关闭音频
            if (res && this._audioData.effectCtrl) {
                let id = cc.audioEngine.playEffect(res, loop)
                this._effect.set(clipName,  { id: id, loop: loop })
            }
        })
    }

    /**
     * 停止音效
     * @param clipName 音频名字
     */
    public stopEffect(clipName: string): void {
        if (!this._effect.has(clipName)) return;
        cc.audioEngine.stop(this._effect.get(clipName).id);
        this._effect.delete(clipName);
    }

    /**
     * 停止所有音效
     */
    public stopAllEffect(): void {
        this._effect.forEach((id, clipName) => this.stopMusic(clipName));
    }

    /**
     * 暂停音效
     * @param clipName 音频名字
     */
    public pauseEffect(clipName: string): void {
        if (!this._effect.has(clipName)) return;
        cc.audioEngine.pause(this._effect.get(clipName).id);
    }

    /**
     * 暂停所有音效
     */
    public pauseAllEffect(): void {
        this._effect.forEach((id, clipName) => this.pauseMusic(clipName));
    }

    /**
     * 恢复音效
     * @param clipName 音频名字
     */
    public resumeEffect(clipName: string): void {
        if (!this._effect.has(clipName)) return;
        cc.audioEngine.resume(this._effect.get(clipName).id);
    }

    /**
     * 恢复所有音效
     */
    public resumeAllEffect(): void {
        this._effect.forEach((id, clipName) => this.resumeMusic(clipName));
    }

}
